#include <stdio.h>
#include <unistd.h>
#include <assert.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#define MAX 1024
#define ARGC 64
#define SEP " "
int split(char* commandstr ,char* argv[]){
  assert(commandstr);
  assert(argv);
  argv[0]=strtok(commandstr,SEP);
  if(argv[0]==NULL)return -1;
  int i=1;
  while(argv[i++]=strtok(NULL,SEP));
  return 0;
}

void showEnv(){
  extern char** environ;
  int i=0;
  for(i=0;environ[i];++i){
    printf("%d:%s\n",i,environ[i]);
  }
}
int main(){
  int last_exit=0;
  char myenv[32][256]={0};
  int env_index=0;
  while(1){
    char commandstr[MAX]={0};
    char* argv[ARGC]={NULL};
    printf("[lisi@我的学习机 newpath]# ");
    fflush(stdout);
    char* s = fgets(commandstr,sizeof(commandstr),stdin);
    assert(s);//保证release方式发布的时候，因为去掉assert了，所以s就没有被使用，而带来的编译告警
    commandstr[strlen(commandstr)-1]='\0';
    int n = split(commandstr,argv);
    if(n!=0)continue;
    if(strcmp(argv[0],"ls")==0){
      int pos=0;
      while(argv[pos])pos++;
      //ls之后显示系统的配色方案
      argv[pos++]="--color=auto";
    }else if(strcmp(argv[0],"cd")==0){
        //cd命令不能交给子进程执行，否则更改的是子进程的路径，必须交给bash执行
        if(argv[1])chdir(argv[1]);
        continue;
    }else if(strcmp(argv[0],"env")==0){
        showEnv();
        continue;
    }else if(strcmp(argv[0],"export")==0){
      if(argv[1]){
        strcpy(myenv[env_index],argv[1]);
        putenv(myenv[env_index++]);
      } 
      continue;
    }else if(strcmp(argv[0],"echo")==0){
      const char* target_env = NULL;
      if(argv[1][0]=='$'){
        if(argv[1][1]=='?'){
          printf("%d\n",last_exit);
          continue;
        }
        else target_env=getenv(argv[1]+1);
        if(target_env)printf("%s:%s\n",argv[1]+1,target_env);
      }
      continue;
    }

    pid_t id = fork();
    assert(id>=0);
    (void)id;
    if(id == 0)
    {
      execvp(argv[0],argv);
      exit(1);
    }
    int status=0;
    pid_t ret  = waitpid(id,&status,0);
    if(ret > 0)
      last_exit=WEXITSTATUS(status);
  }
  return 0;
}
